package library;

/***
 * @author Ragnvald Fuglestein
 */

import java.io.IOException;
import java.util.HashMap;

import callback.ImportArtistCallback;

import baseStructure.Album;
import baseStructure.Artist;
import baseStructure.Log;
import baseStructure.SearchArtist;
import baseStructure.SearchTrack;
import baseStructure.SortedList;
import baseStructure.Track;

public class Library implements ImportArtistCallback {
	private static Library instance = new Library();
	public static Library getInstance() {
		return instance;
	}
	
	private Library() {}
	
	public SortedList<Artist> artists = new SortedList<>(600, 50);
	public HashMap<String, PlayList> playlists = new HashMap<>();
	public LibraryBackend backend = null;
	
	public void setLibraryBackend(LibraryBackend librarybackend) {
		this.backend = librarybackend;
		Log.i(String.format("Set " + backend.toString() + " as library backend"));
	}
	
	/***
	 * Reduce memory usage by resizing lists to their minimal length
	 */
	public void shrinkLibrary() {
		for (Artist ar : artists) {
			SortedList<Album> alist = ar.getAlbums();
			for (Album al : alist) {
				al.getTracks().trimToSize();
			}
			alist.trimToSize();
			ar.getTracks().trimToSize();
		}
		artists.trimToSize();
	}
	
	public void exportLibrary() {
		if (this.backend == null) return;
		shrinkLibrary();
		try {
			this.backend.writeAll(artists);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(e); //Temp
		}
		Log.i(String.format("Exported " + artists.size() + " artists to " + backend.toString()));
	}
	
	public void readArtistsFromBackend() {
		if (backend == null) return;
		SortedList<Artist> list;
		list = (SortedList<Artist>) this.backend.getAll();
		if (list == null) {
			Log.d("Error reading artists from backend");
		}
		Log.i(String.format("Imported " + list.size() + " artists from " + backend.toString()));
		importArtists(list);
	}
	
	/***
	 * Fill list with all artists from library matching search
	 * @param list
	 * @param search
	 */
	public void getArtists(final SortedList<Artist> list, final SearchArtist search) {
		for (Artist a : artists) {
			if (a == null) try {
				Log.d("Library.getArtists");
				Thread.sleep(2000);
			} catch (InterruptedException e) { }
			if (search.matches(a)) list.add(a);
		}
	}
	
	/***
	 * Fill list with all tracks from library matching search
	 * @param list
	 * @param search
	 */
	public void getTracks(final SortedList<Track> list, final SearchTrack search) {
		SearchArtist searchartist;
		
		if ((searchartist = search.getSearchArtist()) != null) {
			SortedList<Artist> l = new SortedList<>();
			getArtists(l, searchartist);
			for (Artist artist : l) {
				artist.getTracks(list, search);
			}
		}
		else {
			for (Artist artist: artists) {
				artist.getTracks(list, search);
			}
		}
	}
	
	/***
	 * Add artist to library if it is not already there
	 * @param artist
	 * @return true if artist was added
	 */
	public boolean addArtist(final Artist artist) {
		if (!artists.contains(artist)) {
			return artists.add(artist);
		}
		return false;
	}
	
	public boolean removeArtist(final Artist artist) {
		return artists.remove(artist);
	}
	
	@Override public void importArtists(SortedList<Artist> list) {
		Log.i(String.format("Merging " + list.size() + " artists to library"));
		for (Artist artist : list) {
			mergeArtist(artist);
		}
	}
	
	/***
	 * Merges artist with an artist already in library, or creates a new one if no existing artist is found
	 * @param artist
	 */
	public void mergeArtist(Artist artist) {
		SortedList<Artist> al = new SortedList<>();
		artists.getMatch(al, artist.toSearch());
		int s = al.size();
		if (s == 1) {
			al.get(0).merge(artist);
		} else if (s == 0) {
			addArtist(artist);
		} else {
			Log.e("Can not merge with more than one artist automatically: ");
			Log.e(artist.toString());
			Log.e("Matches:");
			Log.e(al.toString());
		}
	}
}
